import { BlockState, GameType } from "./content";
import SoundMgr from "../../../general/Script/mgr/soundManager";
import BlockGmMgr from "./blockGMMgr";
import AddScore from "./prefab/addScore";
import Block from "./prefab/block";

import BlockTouch from "./prefab/blockTouch";
import Comb from "./prefab/comb";
import GameMgr from "../../../general/Script/mgr/gameManager";
import { g_bundleName } from "../../../general/Script/mgr/assetsManager";
import NativeMgr from "../../../general/Script/mgr/nativeManager";

const gameRow = 8;
const gameCol = 8;
const BlockColor = 7;

export default class BlockGMLogic {
    node: cc.Node;
    mgr: BlockGmMgr;

    changeNodeArr: cc.Node[] = [];
    addDiamondNodeArr: any[] = [];

    clearNodeArr: cc.Node[] = [];
    clearRow: any[] = [];
    clearCol: any[] = [];

    adTime: number = 0;

    actionPos: cc.Vec2 = null;

    constructor(node: cc.Node, mgr: BlockGmMgr) {
        this.node = node;
        this.mgr = mgr;
        // this.adTime = Date.now()
    }

    initMap(map) {

        for (let i = 0; i < gameRow; i++) {
            for (let j = 0; j < gameCol; j++) {
                const node = cc.instantiate(this.mgr.blockPrefab);
                this.mgr.blockGame.addChild(node);
                const block = node.getComponent(Block);
                const splice = map[i][j].split('_');
                block.init(i, j, Number(splice[0]), Number(splice[1]));
                // if(map[i][j] ){
                //     block.init(i,j,BlockState.show,map[i][j]-1);
                // }else{
                //     block.init(i,j,BlockState.none,0);
                // }

            }
        }




    }


    refreshMap(map) {

        for (let i = 0; i < gameRow; i++) {
            for (let j = 0; j < gameCol; j++) {
                const node = this.mgr.blockGame.getChildByName(i + '_' + j);
                const block = node.getComponent(Block);

                const splice = map[i][j].split('_');
                block.init(i, j, Number(splice[0]), Number(splice[1]));

                // if(map[i][j] ){
                //     block.init(i,j,BlockState.show,map[i][j]-1);
                // }else{
                //     block.init(i,j,BlockState.none,0);
                // }
            }
        }
    }


    createTouchBlock(arr: number[], diamondArr: string[][]) {
        const posx = [-200, 0, 200];
        for (let i = 0; i < arr.length; i++) {
            if (arr[i] === -1) {
                continue;
            }
            const node = cc.instantiate(this.mgr.blockTouches[arr[i]]);
            this.mgr.blockNew.addChild(node);
            const type = Math.floor(Math.random() * BlockColor);
            node.x = posx[i];
            node.getComponent(BlockTouch).init(type, i, diamondArr[i]);

        }

        console.log('this.mgr.blockEffect.children = ', this.mgr.blockEffect.children);
        for (let i in this.mgr.blockEffect.children) {
            if (arr[i] === -1) {
                continue;
            }
            console.log('i = ', i);
            const node = this.mgr.blockEffect.children[i];
            node.opacity = 255;
            node.scale = 0.01;
            node.runAction(cc.sequence(cc.scaleTo(0.1, 1), cc.fadeOut(0.5)));
        }


    }


    getRolCol(pos: cc.Vec2) {
        const startPos = cc.v2(-289.5 - 40, 291.5 + 40)
        const endPos = cc.v2(-289.5 + 40, 291.5 - 40)
        const add = cc.v2(3, 3);



        const x = pos.x;
        const y = pos.y;
        const row = Math.floor((startPos.y - y) / 81.5);
        const col = Math.floor((x - startPos.x) / 81.5);
        return { row, col }
    }

    checkCanPut() {
        const pos = this.mgr.touchNode.getComponent(BlockTouch).getWorldPos();
        const posGame = this.mgr.blockGame.convertToNodeSpaceAR(pos);
        // console.log('pos',posGame.x,posGame.y);

        const rolCol = this.getRolCol(posGame);
        // console.log('rolCol:',rolCol);

        const blockTouch = this.mgr.touchNode.getComponent(BlockTouch);

        const indexArr = blockTouch.getBlockIndexArr();
        const blockType = blockTouch.getBlockType()



        const willChangeNode: cc.Node[] = []
        for (let i in indexArr) {
            const row = rolCol.row + indexArr[i][0];
            const col = rolCol.col + indexArr[i][1];
            if (row < 0 || row >= gameRow || col < 0 || col >= gameCol) {
                break;
            }
            const name = `${row}_${col}`;
            const node = this.mgr.blockGame.getChildByName(name);
            if (node == null) {
                break;
            }
            const block = node.getComponent(Block);
            // console.log('block.state:',block.state,block.row,block.col,block.blockType);
            if (block.state != BlockState.none && block.state != BlockState.mid) {
                break;
            }

            willChangeNode.push(node);

        }

        if (willChangeNode.length < indexArr.length) {
            //预设变回
            if (this.changeNodeArr.length > 0) {
                for (let i in this.changeNodeArr) {
                    const node = this.changeNodeArr[i];
                    const block = node.getComponent(Block);
                    block.changeState(BlockState.none, 0);
                }
                this.changeNodeArr = [];
            }

            //增加钻石变回
            if (this.addDiamondNodeArr.length > 0) {
                this.addDiamondNodeArr = [];
            }

            //消除变回
            if (this.clearNodeArr.length > 0) {


                for (let i in this.clearNodeArr) {
                    const node = this.clearNodeArr[i];
                    const block = node.getComponent(Block);
                    if (block.state === BlockState.clear) {
                        block.changeState(BlockState.show, block.blockType);
                    }

                }
                this.clearNodeArr = [];
                this.clearRow = [];
                this.clearCol = [];




            }

            // console.log('can not put',willChangeNode.length,indexArr);
            return;
        }

        //需要变色的
        for (let i in willChangeNode) {
            const node = willChangeNode[i];
            const block = node.getComponent(Block);
            block.changeState(BlockState.mid, blockType);
        }

        //之前需要变色的块
        for (let i in this.changeNodeArr) {
            const node = this.changeNodeArr[i];
            if (willChangeNode.indexOf(node) == -1) {
                const block = node.getComponent(Block);
                block.changeState(BlockState.none, 0);
            }
        }

        this.changeNodeArr = willChangeNode;

        this.addDiamondNodeArr = [];
        //变钻石块索引id
        const diamondArr = blockTouch.getDiamondArr();
        for (let i in diamondArr) {
            const info = diamondArr[i];
            //  console.log('info:',info);
            //  console.log('rolCol:',rolCol);
            const infoArr = info.split('_');
            const row = Number(rolCol.row) + Number(infoArr[0]);
            const col = Number(rolCol.col) + Number(infoArr[1]);

            this.addDiamondNodeArr.push({
                row,
                col,
                type: Number(infoArr[2])
            });
        }

        this.checkCanClear();

    }

    checkCanClear() {
        const rowArr = [];
        const colArr = [];

        const removeTouchBlock = [];
        if (this.clearNodeArr.length > 0) {
            for (let i in this.clearNodeArr) {
                const node = this.clearNodeArr[i];
                const block = node.getComponent(Block);
                if (block.state === BlockState.clear) {
                    block.changeState(BlockState.show, block.blockType);
                }
            }
            this.clearNodeArr = [];
            this.clearRow = [];
            this.clearCol = [];
        }


        for (let i in this.changeNodeArr) {
            const node = this.changeNodeArr[i];
            const block = node.getComponent(Block);
            if (rowArr.indexOf(block.row) == -1) {
                rowArr.push(block.row);
            }
            if (colArr.indexOf(block.col) == -1) {
                colArr.push(block.col);
            }
        }

        // console.log('rowArr:',rowArr);
        //  console.log('colArr:',colArr);

        const clearRowArr = [];
        const clearColArr = [];

        const blockType = this.mgr.touchNode.getComponent(BlockTouch).getBlockType();
        for (let i in rowArr) {
            const row = rowArr[i];
            let clearNum = 0;
            for (let col = 0; col < gameCol; col++) {
                const node = this.mgr.blockGame.getChildByName(`${row}_${col}`);
                if (node == null) {
                    break;
                }
                const block = node.getComponent(Block);
                if (block.state === BlockState.none) {
                    break;
                }
                clearNum++;
            }

            if (clearNum === gameCol) {
                clearRowArr.push(row);
                for (let col = 0; col < gameCol; col++) {
                    const node = this.mgr.blockGame.getChildByName(`${row}_${col}`);
                    if (this.clearNodeArr.indexOf(node) == -1) {
                        this.clearNodeArr.push(node);
                        const block = node.getComponent(Block);
                        if (block.state === BlockState.show) {
                            node.getComponent(Block).changeState(BlockState.clear, blockType);
                        } else if (block.state === BlockState.mid) {
                            if (removeTouchBlock.indexOf(node) == -1) {
                                removeTouchBlock.push(node);
                            }
                        }

                    }
                }
            }
        }


        for (let i in colArr) {
            const col = colArr[i];
            let clearNum = 0;
            for (let row = 0; row < gameRow; row++) {
                const node = this.mgr.blockGame.getChildByName(`${row}_${col}`);
                if (node == null) {
                    break;
                }
                const block = node.getComponent(Block);
                if (block.state === BlockState.none) {
                    break;
                }
                clearNum++;
            }
            if (clearNum === gameRow) {
                clearColArr.push(col);
                for (let row = 0; row < gameRow; row++) {
                    const node = this.mgr.blockGame.getChildByName(`${row}_${col}`);
                    if (this.clearNodeArr.indexOf(node) == -1) {
                        this.clearNodeArr.push(node);
                        const block = node.getComponent(Block);
                        if (block.state === BlockState.show) {
                            node.getComponent(Block).changeState(BlockState.clear, blockType);
                        } else if (block.state === BlockState.mid) {
                            if (removeTouchBlock.indexOf(node) == -1) {
                                removeTouchBlock.push(node);
                            }
                        }
                    }
                }
            }
        }


        // console.log('clearRowArr:',clearRowArr);
        // console.log('clearColArr:',clearColArr);
        if (clearRowArr.length > 0 || clearColArr.length > 0) {
            this.mgr.data.setAddScore(clearRowArr.length, clearColArr.length);
            this.clearRow = clearRowArr;
            this.clearCol = clearColArr;
        }


        if (removeTouchBlock.length > 0) {
            const index = Math.floor(Math.random() * removeTouchBlock.length);
            this.actionPos = removeTouchBlock[index].getPosition();
        }


    }





    putBlock() {


        GameMgr.Ins().emit('game_addStep');
        GameMgr.Ins().emit('game_addScore', this.changeNodeArr.length, false);



        for (let i in this.changeNodeArr) {
            const node = this.changeNodeArr[i];
            const block = node.getComponent(Block);
            block.changeState(BlockState.show, block.blockType);
            this.mgr.data.changeMap(block.row, block.col, BlockState.show, block.blockType);
        }
        this.changeNodeArr = [];

        // console.log('this.addDiamondNodeArr:',this.addDiamondNodeArr)
        for (let i in this.addDiamondNodeArr) {
            const info = this.addDiamondNodeArr[i];
            const row = info.row;
            const col = info.col;
            const type = info.type;
            const node = this.mgr.blockGame.getChildByName(`${row}_${col}`);
            const block = node.getComponent(Block);
            block.changeState(BlockState.star, type);
            this.mgr.data.changeMap(block.row, block.col, BlockState.star, type);
        }
        this.addDiamondNodeArr = [];


        const blockIndex = this.mgr.touchNode.getComponent(BlockTouch).getTouchIndex();
        this.mgr.data.changeTouchBlock(blockIndex);


    }

    canClear() {
        return this.clearNodeArr.length > 0;
    }

    clearBlocks(cb) {


        if (this.clearNodeArr.length > 0) {




            const lines = this.clearRow.length + this.clearCol.length;

            for (let i in this.clearNodeArr) {
                const node = this.clearNodeArr[i];
                const block = node.getComponent(Block);
                if (block.state === BlockState.stone) {
                    continue;
                }
                if (block.state === BlockState.star) {
                    this.diamondNodeAction(block.starType, node);
                }
                block.changeState(BlockState.none, 0);
                this.mgr.data.changeMap(block.row, block.col, BlockState.none, 1);
            }
            this.clearNodeArr = [];

            const blockType = this.mgr.touchNode.getComponent(BlockTouch).getBlockType();

            for (let i in this.clearRow) {
                const row = this.clearRow[i];
                const node = this.mgr.blockGameEffectRow.getChildByName(row.toString());
                node.getComponent(Block).setBlockType(blockType);
                // node.active = true;
                node.opacity = 255;
                node.scaleX = 0.1;
                node.scaleY = 0.1;
                node.runAction(cc.sequence(cc.delayTime(0.15), cc.fadeOut(0.4)));
                node.runAction(cc.sequence(cc.scaleTo(0.1, 1, 0.1).easing(cc.easeIn(2)), cc.scaleTo(0.2, 1).easing(cc.easeIn(2)), cc.callFunc(() => {
                    // node.active = false;
                })));
            }


            for (let i in this.clearCol) {
                const col = this.clearCol[i];
                const node = this.mgr.blockGameEffectCol.getChildByName(col.toString());
                node.getComponent(Block).setBlockType(blockType);
                // node.active = true;
                node.opacity = 255;
                node.scaleX = 0.1;
                node.scaleY = 0.1;
                node.runAction(cc.sequence(cc.delayTime(0.15), cc.fadeOut(0.4)));
                node.runAction(cc.sequence(cc.scaleTo(0.1, 0.1, 1).easing(cc.easeIn(2)), cc.scaleTo(0.2, 1).easing(cc.easeIn(2)), cc.callFunc(() => {
                    // node.active = false;
                })));


            }

            this.clearRow = [];
            this.clearCol = [];

            this.mgr.data.addCombTimes();
            this.mgr.data.setCombScore();

            // SoundMgr.Ins().playEffect('block_clear');



            //播放加分动画
            // this.mgr.scoreEffect
            // this.actionPos
            this.addScoreAction(this.mgr.data.wantAddScore, lines);


            this.addAds()

            this.mgr.scheduleOnce(() => {
                GameMgr.Ins().emit('game_addScore', this.mgr.data.wantAddScore, true);
                cb();
            }, 1);
        }

    }

    addAds() {

        this.adTime++;
        console.log('this.adTime = ', this.adTime);
        if (this.adTime > 4) {
            this.adTime = 0;
            // NativeMgr.Ins().showExpressAds();
            cc.systemEvent.emit('showExpressAdInGame', 1);
        }
    }

    diamondNodeAction(diamondType: Number, node: cc.Node) {
        const diamondNode = this.mgr.blockStar;
        const toNode = diamondNode.getChildByName(diamondType.toString());
        const newNode = toNode.getChildByName('star');
        const starNode = cc.instantiate(newNode);
        diamondNode.addChild(starNode);
        starNode.x = node.x;
        starNode.y = node.y;
        starNode.scale = 0;



        starNode.runAction(cc.sequence(cc.delayTime(0.2), cc.scaleTo(0.3, 1.8).easing(cc.easeIn(2)), cc.scaleTo(0.2, 1).easing(cc.easeOut(2)),
            cc.delayTime(0.5), cc.moveTo(0.4, toNode.x, toNode.y).easing(cc.easeIn(3)),
            cc.callFunc(() => {
                this.nodeScaleAction(toNode);
                starNode.removeFromParent(true);
                starNode.destroy();
                GameMgr.Ins().emit('game_addStar', diamondType);
            })));
    }

    nodeScaleAction(node: cc.Node) {
        node.stopAllActions();
        node.scale = 1;
        node.runAction(cc.sequence(cc.scaleTo(0.12, 1.5).easing(cc.easeIn(2)), cc.scaleTo(0.08, 1).easing(cc.easeOut(2))));
    }

    addScoreAction(score, line) {

        const parent = this.mgr.scoreEffect;

        const blockType = this.mgr.touchNode.getComponent(BlockTouch).getBlockType();

        //先判断comb comb>1 先放comb；
        this.actionPos.x = Math.max(this.actionPos.x, -240);
        this.actionPos.x = Math.min(this.actionPos.x, 250);


        const combTimes = this.mgr.data.getCombTimes();

        if (combTimes > 1) {
            SoundMgr.Ins().playEffect(`bg_effect_comb_${Math.min(combTimes, 5)}`, g_bundleName.gameBlock);
            const combNode = cc.instantiate(this.mgr.combPrefab);
            parent.addChild(combNode);
            combNode.setPosition(this.actionPos);
            combNode.getComponent(Comb).setNumber(combTimes);

            combNode.getComponent(Comb).runCombAction(() => {

                if (this.mgr.gameType === GameType.normal || this.mgr.gameType === GameType.score) {
                    const node = cc.instantiate(this.mgr.addScorePrefab);
                    parent.addChild(node);
                    node.setPosition(this.actionPos);

                    const effectType = node.getComponent(AddScore).setScoreAndLine(score, line, blockType);

                    node.getComponent(AddScore).runScoreAction();
                    SoundMgr.Ins().playEffect(`effect_${effectType}`, g_bundleName.gameBlock);
                }

            });

            if (combTimes > 2) {
                const action = cc.sequence(
                    cc.moveBy(0.02, cc.v2(2, 2)),
                    cc.moveBy(0.03, cc.v2(0, -4)),
                    cc.moveBy(0.05, cc.v2(-4, 4)),
                    cc.moveBy(0.03, cc.v2(0, -4)),
                    cc.moveBy(0.02, cc.v2(2, 2)),
                    cc.moveBy(0.02, cc.v2(2, 2)),
                    cc.moveBy(0.03, cc.v2(0, -4)),
                    cc.moveBy(0.05, cc.v2(-4, 4)),
                    cc.moveBy(0.03, cc.v2(0, -4)),
                    cc.moveBy(0.02, cc.v2(2, 2)),
                );
                this.mgr.node.runAction(action);
                // this.mgr.blockGameEffectCol.runAction(action.clone());
                // this.mgr.blockGameEffectRow.runAction(action.clone());
                // this.mgr.scoreEffect.runAction(action.clone());

            }

        } else {
            SoundMgr.Ins().playEffect('bg_effect_comb_1', g_bundleName.gameBlock);
            if (this.mgr.gameType === GameType.normal || this.mgr.gameType === GameType.score) {
                const node = cc.instantiate(this.mgr.addScorePrefab);
                parent.addChild(node);
                node.setPosition(this.actionPos);

                const effectType = node.getComponent(AddScore).setScoreAndLine(score, line, blockType);

                node.getComponent(AddScore).runScoreAction();
                SoundMgr.Ins().playEffect(`effect_${effectType}`, g_bundleName.gameBlock);
            }
        }

    }


    updateScore(score) {
        // console.log('score = ',score);
        const scoreOld = this.mgr.scoreNode.getComponent(cc.Label).string
        const def = score - Number(scoreOld);
        const step = 5;
        let time = 1;

        const repeat = (def < 5 && def > 0) ? def - 1 : 4;


        this.mgr.schedule(() => {
            let scoreSet = def / step * time + Number(scoreOld);
            if (def > 0) {
                scoreSet = Math.max(scoreSet, time + Number(scoreOld));
            }

            //  console.log('scoreSet = ',scoreSet);
            this.mgr.scoreNode.getComponent(cc.Label).string = Math.floor(scoreSet).toString();
            time++;
        }, 0.05, repeat);

    }


    updateLeftScore(score, cb: Function = null) {
        //  console.log('score = ',score);
        const node = this.mgr.scoreLeft.getChildByName('score')
        const scoreOld = node.getComponent(cc.Label).string
        if (scoreOld === '0') {
            node.getComponent(cc.Label).string = score.toString();
            return;
        }
        const def = Number(scoreOld) - score;
        const step = 5;
        let time = 1;

        const repeat = (def < 5 && def > 0) ? def - 1 : 4;


        this.mgr.schedule(() => {
            let scoreSet = Number(scoreOld) - def / step * time;
            if (def > 0) {
                scoreSet = Math.min(scoreSet, Number(scoreOld) - time);
            }
            if (scoreSet < 0) {
                scoreSet = 0;
            }
            //  console.log('scoreSet = ',scoreSet);
            node.getComponent(cc.Label).string = Math.floor(scoreSet).toString();

            time++;
        }, 0.05, repeat);

        this.mgr.scheduleOnce(() => {
            cb && cb()
        }, 0.5);
    }

    updateLeftStep(step) {

        const node = this.mgr.blockStep.getChildByName('score')
        node.getComponent(cc.Label).string = step;


    }

    updateLeftDiamond(diamondArr) {
        for (let i in diamondArr) {
            const node = this.mgr.blockStar.getChildByName(i.toString());
            const left = node.getChildByName('left').getComponent(cc.Label);
            left.string = diamondArr[i];
        }

    }



    checkGameOver() {
        let gameOver = true;
        const nodes = this.mgr.blockNew.children;
        for (let n in nodes) {
            const blockTouch = nodes[n].getComponent(BlockTouch);
            for (let i = 0; i < gameRow; i++) {
                for (let j = 0; j < gameCol; j++) {
                    const node = this.mgr.blockGame.getChildByName(i + '_' + j);
                    const block = node.getComponent(Block);
                    // if(block.state !== BlockState.none){
                    //     continue;
                    // }
                    const rolCol = { row: i, col: j };


                    const indexArr = blockTouch.getBlockIndexArr();

                    const willChangeNode: cc.Node[] = []
                    for (let i in indexArr) {
                        const row = rolCol.row + indexArr[i][0];
                        const col = rolCol.col + indexArr[i][1];
                        if (row < 0 || row >= gameRow || col < 0 || col >= gameCol) {
                            break;
                        }
                        const name = `${row}_${col}`;
                        const node = this.mgr.blockGame.getChildByName(name);
                        if (node == null) {
                            break;
                        }
                        const block = node.getComponent(Block);
                        if (block.state != BlockState.none && block.state != BlockState.mid) {
                            break;
                        }

                        willChangeNode.push(node);
                    }
                    if (willChangeNode.length == indexArr.length) {
                        return false
                        break;
                    }
                }
            }
        }

        return true;


    }

    gameStart(cb) {
        const delayOne = 0.1;
        SoundMgr.Ins().playEffect('block_start', g_bundleName.gameBlock);
        for (let i = gameRow - 1; i >= 0; i--) {
            for (let j = 0; j < gameCol; j++) {
                const node = this.mgr.blockGame.getChildByName(i + '_' + j);
                const block = node.getComponent(Block);


                const delayTime = delayOne * (gameRow - i);
                node.runAction(cc.sequence(cc.delayTime(delayTime), cc.callFunc(() => {
                    if (block.state === BlockState.none) {
                        block.changeState(BlockState.showGame, Math.floor(Math.random() * BlockColor));
                    }

                })));

            }
        }
        let delay = delayOne * gameRow + 0.2
        for (let i = 0; i < gameRow; i++) {
            for (let j = 0; j < gameCol; j++) {
                const node = this.mgr.blockGame.getChildByName(i + '_' + j);
                const block = node.getComponent(Block);


                const delayTime = delayOne * i + delay;
                node.runAction(cc.sequence(cc.delayTime(delayTime), cc.callFunc(() => {
                    if (block.state === BlockState.showGame) {
                        block.changeState(BlockState.none, Math.floor(Math.random() * BlockColor));
                    }

                })));

            }
        }

        this.mgr.node.runAction(cc.sequence(cc.delayTime(delayOne * gameRow * 2), cc.callFunc(() => {
            cb();
        })));
    }


    gameOver(overTime: number = 0) {


        SoundMgr.Ins().playEffect('block_over', g_bundleName.gameBlock);
        const delayStart = overTime
        // for(let i = gameRow-1; i >= 0; i--){
        //     for(let j = 0; j < gameCol; j++){
        //         const node = this.mgr.blockGame.getChildByName(i + '_' + j);
        //         const block = node.getComponent(Block);


        //         const delayTime = 0.1*(gameRow-i)+delayStart;
        //         node.runAction(cc.sequence(cc.delayTime(delayTime),cc.callFunc(()=>{

        //             block.changeState(BlockState.show,Math.floor(Math.random() * BlockColor));


        //         })));

        //     }
        // }

        const delaybase2 = delayStart //+0.1*gameRow;

        for (let i = 0; i < gameRow; i++) {
            for (let j = 0; j < gameCol; j++) {
                const node = this.mgr.blockGame.getChildByName(i + '_' + j);
                const block = node.getComponent(Block);
                if (block.state === BlockState.none) {
                    continue
                }
                const delayTime = Math.random() * 1 + delaybase2;
                node.runAction(cc.sequence(cc.delayTime(delayTime), cc.callFunc(() => {

                    block.changeState(BlockState.over, Math.floor(Math.random() * BlockColor));


                })));
            }
        }

    }


}